package service

import (
	"aiRole/internal/dao/model"
	"aiRole/internal/dao/query"
	"aiRole/internal/dto/request"
	result "aiRole/internal/dto/reslult"
	initSystem "aiRole/pkg/init"
	"aiRole/pkg/util"
	"context"
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"gopkg.in/gomail.v2"
	"gorm.io/gorm"
	"math/big"
	"strconv"
	"time"
)

type AuthService struct {
}

func (s AuthService) Login(c *gin.Context, req request.UserLoginRequest) {
	userDB := query.Use(initSystem.DB).User
	userInfo, err := userDB.WithContext(context.TODO()).Where(userDB.Username.Eq(req.Username)).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "服务器错误")
		return
	}

	if errors.Is(err, gorm.ErrRecordNotFound) {
		result.Error(c, 500, "用户不存在")
		return
	}
	isLogin := util.CheckPassword(userInfo.Password, req.Password)
	if !isLogin {
		result.Error(c, 403, "密码错误")
		return
	}
	//TODO 后期改为JWT
	token, _ := util.GenerateJWT(strconv.FormatInt(userInfo.ID, 10))
	data, err := json.Marshal(userInfo)
	if err != nil {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "服务器错误")
		return
	}
	initSystem.RDB.Set(context.TODO(), "user:"+strconv.FormatInt(userInfo.ID, 10), data, time.Hour*24*3)
	result.Ok(c, gin.H{"token": token})
}

func (s AuthService) Register(c *gin.Context, req request.UserRegisterRequest) {
	userDB := query.Use(initSystem.DB).User
	userInfo, err := userDB.WithContext(context.TODO()).Where(userDB.Username.Eq(req.Username)).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "服务器错误")
	}
	if userInfo != nil || !errors.Is(err, gorm.ErrRecordNotFound) {
		result.Error(c, 500, "用户名已存在")
		return
	}
	//查询DB判断邮箱是否重复
	first, err := userDB.WithContext(context.TODO()).Where(userDB.Email.Eq(req.Email), userDB.Email.Neq("")).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "服务器错误")
	}
	if first != nil {
		result.Error(c, 500, "邮箱已存在")
		return
	}
	user := model.User{}
	user.Username = req.Username
	hashPassword, err := util.HashPassword(req.Password)
	if err != nil {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "服务器错误")
		return
	}
	user.Email = req.Email
	user.Password = hashPassword
	err = userDB.WithContext(context.TODO()).Create(&user)
	if err != nil {
		initSystem.Logger.Error(err.Error())
		result.Error(c, 500, "注册失败")
		return
	}
	result.Ok(c, "注册成功!")
}

func (s AuthService) SendCode(c *gin.Context, email string) {
	//TODO 发送验证码
	//限流
	ok, _ := initSystem.RDB.SetNX(c, "code:qps:"+email, 1, 5*time.Minute).Result()
	if !ok {
		result.Error(c, 500, "发送验证码过于频繁,请一分钟后重试")
		return
	}
	code, err := SendVerifyCode(email)
	if err != nil {
		result.Error(c, 500, "发送验证码失败")
		return
	}
	//存储code
	go initSystem.RDB.Set(context.TODO(), "code:"+email, code, time.Minute*5)
	result.Ok(c, "发送验证码成功!")
}

func SendVerifyCode(to string) (string, error) {
	// 1. 邮箱配置（改成你自己的）
	from := viper.GetString("email.from")
	password := viper.GetString("email.password")
	smtpHost := viper.GetString("email.host")
	smtpPort := 465

	// 2. 生成6位数字验证码
	code := ""
	for i := 0; i < 6; i++ {
		n, _ := rand.Int(rand.Reader, big.NewInt(10))
		code += n.String()
	}

	// 3. 构建邮件内容
	m := gomail.NewMessage()
	m.SetHeader("From", from)
	m.SetHeader("To", to)
	m.SetHeader("Subject", "Title")
	m.SetBody("text/plain", fmt.Sprintf("您的验证码是：%s，有效期5分钟。", code))

	// 4. 发送邮件
	d := gomail.NewDialer(smtpHost, smtpPort, from, password)
	if err := d.DialAndSend(m); err != nil {
		return "", err
	}

	return code, nil
}
